Serving Static Files with Hapi and Docker 您所在的位置:网站首页 Serving static files in Express Serving Static Files with Hapi and Docker

Serving Static Files with Hapi and Docker

2023-09-17 14:20| 来源: 网络整理| 查看: 265

Serving Static Files with Hapi and Docker

Installing hapiCreating a ServerAdding RoutesServing Static ContentFile HandlerDirectory HandlerGatsby ServerDocker it!

I need to build a web server for static files generated by Gatsby.js. So far I was using Express.js to do this. But there seems to be a new library that is gaining popularity among my coworkers called Hapi.js. Let's see if we can make this work for us.

Installing hapi​Create a new directory gatsby-static, and from there:cd gatsby-staticnpm initnpm install @hapi/hapi

This will install the latest version of hapi as a dependency in your package.json.

Creating a Server​

A very basic hapi server looks like the following:

'use strict';const Hapi = require('@hapi/hapi');const init = async () => { const server = Hapi.server({ port: 3000, host: '0.0.0.0' }); await server.start(); console.log('Server running on %s', server.info.uri);};process.on('unhandledRejection', (err) => { console.log(err); process.exit(1);});init();Adding Routes​

After you get the server up and running, its time to add a route that will display "Hello World!" in your browser.

'use strict';const Hapi = require('@hapi/hapi');const init = async () => { const server = Hapi.server({ port: 3000, host: '0.0.0.0' }); server.route({ method: 'GET', path: '/', handler: (request, h) => { return 'Hello World!'; } }); await server.start(); console.log('Server running on %s', server.info.uri);};process.on('unhandledRejection', (err) => { console.log(err); process.exit(1);});init();

Save the above as app.js and start the server with the command node app.js. Now you'll find that if you visit http://localhost:3000 in your browser, you'll see the text Hello, World!.

Serving Static Content​

There is a hapi plugin called inert that adds this functionality to hapi through the use of additional handlers. First you need to install and add inert as a dependency to your project:

npm install @hapi/inertFile Handler​

The inert plugin provides new handler methods for serving static files and directories, as well as adding a h.file() method to the toolkit, which can respond with file based resources. To simplify things, especially if you have multiple routes that respond with files, you can configure a base path in your server and only pass relative paths to h.file():

'use strict';const Path = require('path');const Hapi = require('@hapi/hapi');const Path = require('path');const start = async () => { const server = Hapi.server({ routes: { files: { relativeTo: Path.join(__dirname, 'public') } } }); await server.register(require('@hapi/inert')); server.route({ method: 'GET', path: '/picture.jpg', handler: function (request, h) { return h.file('picture.jpg'); } }); await server.start(); console.log('Server running at:', server.info.uri);};start();

Note that you need to npm install path into your project to work with the Gatsby.js public directory.

Directory Handler​

In addition to the file handler, inert also adds a directory handler that allows you to specify one route to serve multiple files. In order to use it, you must specify a route path with a parameter. The name of the parameter does not matter, however. You can use the asterisk extension on the parameter to restrict file depth as well. The most basic usage of the directory handler looks like:

server.route({ method: 'GET', path: '/{param*}', handler: { directory: { path: 'directory-path-here' } }});

The above route will respond to any request by looking for a matching filename in the directory-path-here directory. Note that a request to / in this configuration will reply with an HTTP 403 response. You can fix this by adding an index file. By default hapi will search in the directory for a file called index.html:

server.route({ method: 'GET', path: '/{param*}', handler: { directory: { path: 'directory-path-here', index: ['index.html'] } }});

A request to / will now first try to load /index.html. When there is no index file available, inert can display the contents of the directory as a listing page. You can enable that by setting the listing property to true like so:

server.route({ method: 'GET', path: '/{param*}', handler: { directory: { path: 'directory-path-here', listing: true } }});

Now a request to / will reply with HTML showing the contents of the directory. When using the directory handler with listing enabled, by default hidden files will not be shown in the listing. That can be changed by setting the showHidden option to true. Like the file handler, the directory handler also has a lookupCompressed option to serve precompressed files when possible. You can also set a defaultExtension that will be appended to requests if the original path is not found. This means that a request for /bacon will also try the file /bacon.html.

Gatsby Server​

One common case for serving static content is setting up a file server. The following example shows how to setup a basic file serve in hapi:

const Path = require('path');const Hapi = require('@hapi/hapi');const Inert = require('@hapi/inert');const init = async () => { const server = new Hapi.Server({ port: 7777, routes: { files: { relativeTo: Path.join(__dirname, 'public') } } }); await server.register(Inert); server.route({ method: 'GET', path: '/{param*}', handler: { directory: { path: '.', redirectToSlash: true } } }); await server.start(); console.log('Server running at:', server.info.uri);};init();

After your server is configured, you then register the inert plugin. This will allow you to have access to the directory handler, which will enable you to server your files. In the directory handler, you configure path, which is required, to look in the entire Gatsby public directory which you specified in the relativeTo option. The second option is the redirectToSlash option. By setting this to true, you tell the server to redirect requests without trailing slashes to the same path with those with the trailing slash.

Docker it!​

I now have a directory gatsby-static that contains the node_modules folder and 3 files - the app.js file (see above) and packages.json (+ package-lock.json):

{ "name": "hapi-container", "version": "1.0.0", "description": "hapi static server", "main": "app.js", "scripts": { "start": "node app.js", "test": "echo \"Error: no test specified\" && exit 1" }, "author": "Mike Polinowski", "license": "MIT", "dependencies": { "@hapi/hapi": "^20.0.0", "@hapi/inert": "^6.0.2", "path": "^0.12.7" }}

Note that I added a start script here. This way I am able to start my app with npm start instead of having to type node app.js.

I will now copy those - but not the public folder with my static files! Also the node_modules does not have to be included inside the image - into a subdirectory called container, create an empty directory called public inside it and create a Dockerfile in the root directory:

my-static-filescontainerpublicapp.jspackage.jsonpackage-lock.jsonDockerfile

The Dockerfile should look like this:

FROM node:latestLABEL maintainer="[email protected]"ENV NODE_ENV=productionENV PORT=7777COPY ./container /wiki_en_ssrWORKDIR /wiki_en_ssrRUN npm installEXPOSE 7777ENTRYPOINT ["npm", "start"]

This will wrap our hapi server inside a docker image once we run the docker build command:

docker build -t wiki-instar-com -f /path/to/a/Dockerfile .Sending build context to Docker daemon 1.563GBStep 1/9 : FROM node:latest ---> 784e696f5060Step 2/9 : LABEL maintainer="[email protected]" ---> Running in 6fd6a2ee6aa1Removing intermediate container 6fd6a2ee6aa1 ---> aae0a3c6671bStep 3/9 : ENV NODE_ENV=production ---> Running in 4b2ffdce8455Removing intermediate container 4b2ffdce8455 ---> 0ff0a5d4528cStep 4/9 : ENV PORT=7777 ---> Running in c4b56a96175dRemoving intermediate container c4b56a96175d ---> 0d7e9b6d66a3Step 5/9 : COPY ./container /wiki_en_ssr ---> f8fad2e28ae9Step 6/9 : WORKDIR /wiki_en_ssr ---> Running in 88f9a237ecf1Removing intermediate container 88f9a237ecf1 ---> 394ad4d346e9Step 7/9 : RUN npm install ---> Running in 96161550ef65npm WARN [email protected] No repository field.added 37 packages from 7 contributors and audited 37 packages in 6.389sfound 0 vulnerabilitiesRemoving intermediate container 96161550ef65 ---> 78a03539837fStep 8/9 : EXPOSE 7777 ---> Running in 1dc2cdaa2eb4Removing intermediate container 1dc2cdaa2eb4 ---> f2c4e7f61583Step 9/9 : ENTRYPOINT ["npm", "start"] ---> Running in bec8b8ed7815Removing intermediate container bec8b8ed7815 ---> 418d52e68b85Successfully built 418d52e68b85Successfully tagged wiki-instar-com:latestdocker build -t wiki-instar-de -f /path/to/a/Dockerfile .docker build -t wiki-instar-fr -f /path/to/a/Dockerfile .

You can now start a container from this image and point it to your folder with static content:

docker run -p 8080:7777 -v /path/to/my-static-files:/wiki_en_ssr/public wiki-instar-com> [email protected] start /wiki_en_ssr> node app.jsServer running at: http://localhost:7777

Note that the path to your static files as well as the public directory inside your container has to be absolute. For example docker run -p 8080:7777 -v /opt/hapi-container-en/app:/wiki_en_ssr/public wiki-instar-com.

To run your container detached from your console use:

docker run -d -p 8080:7777 -v /opt/hapi-container-en/app:/wiki_en_ssr/public --network=wikinet --name wiki_en wiki-instar-comc6a398309919201f63b3bff32436f4a63a35bc17fd1b5dd43b43d0e5ed9ce9e5docker psCONTAINER ID IMAGE COMMAND PORTS NAMESc6a398309919 wiki-instar-com "npm start" 0.0.0.0:8080->7777/tcp wiki_en


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有